﻿namespace NJQuery {
	using System;
	using System.ComponentModel;

	/// <summary>
	/// Defines a predefined or custom <see cref="DatePicker"/> widget animation.
	/// </summary>
	[TypeConverter(typeof(DatePickerAnimationConverter))]
	public struct DatePickerAnimation : IEquatable<DatePickerAnimation>, IComplexProperty {


		#region Static Readonly Fields: Standard values

		/// <summary>
		/// The basic "show" animation will be used by the DatePicker widget when shown.
		/// </summary>
		public static readonly DatePickerAnimation Show = new DatePickerAnimation();

		/// <summary>
		/// The DatePicker widget will use the standard "slideDown" animation when shown.
		/// </summary>
		public static readonly DatePickerAnimation SlideDown = new DatePickerAnimation(DatePickerStandardAnimation.SlideDown);

		/// <summary>
		/// The DatePicker widget will use the standard "fadeIn" animation when shown.
		/// </summary>
		public static readonly DatePickerAnimation FadeIn = new DatePickerAnimation(DatePickerStandardAnimation.FadeIn);

		#endregion


		#region Static Methods

		/// <summary>
		/// Converts a string representation to its <see cref="DatePickerAnimation"/> equivalent.
		/// </summary>
		/// <param name="text">A string containing the value to convert.</param>
		/// <returns>The parsed value.</returns>
		public static DatePickerAnimation Parse(string text) {

			if(string.IsNullOrEmpty(text)) return Show;

			//TODO: Write a Enum.TryParse!!!
			try {
				return new DatePickerAnimation((DatePickerStandardAnimation)Enum.Parse(typeof(DatePickerStandardAnimation), text));
			} catch(ArgumentException) { }
			
			return new DatePickerAnimation(text);
		}

		#endregion


		#region Fields

		private DatePickerStandardAnimation standardAnimation;
		private string controlId;

		#endregion


		#region Constructors

		/// <summary>
		/// Initializes a new <see cref="DatePickerAnimation"/> value using a standard <see cref="DatePicker"/> widget animation definition.
		/// </summary>
		/// <param name="standardAnimation">The <see cref="DatePickerStandardAnimation"/> to use.</param>
		/// <exception cref="ArgumentException">Standard animation not defined.</exception>
		public DatePickerAnimation(DatePickerStandardAnimation standardAnimation) {
			if(!Enum.IsDefined(typeof(DatePickerStandardAnimation), standardAnimation)) throw new ArgumentException("Value not defined.", "standardAnimation");

			this.standardAnimation = standardAnimation;
			controlId = null;
		}

		/// <summary>
		/// Initializes a new <see cref="DatePickerAnimation"/> value using a jQuery UI effect server control definition.
		/// </summary>
		/// <param name="effect">The effect definition to use.</param>
		/// <exception cref="ArgumentNullException">The effect definition value cannot be null.</exception>
		/// <exception cref="ArgumentException">The effect definition must have a control ID specified.</exception>
		public DatePickerAnimation(IEffect effect) {
			if(effect == null) throw new ArgumentNullException("effect");
			if(string.IsNullOrEmpty(effect.ControlId)) throw new ArgumentException("Effect object must have control ID specified.", "effect");

			standardAnimation = DatePickerStandardAnimation.Show;
			controlId = effect.ControlId;
		}

		/// <summary>
		/// Initializes a new <see cref="DatePickerAnimation"/> value using a jQuery UI effect server control definition.
		/// </summary>
		/// <param name="controlId">The control ID of the effect definition to use.</param>
		/// <exception cref="ArgumentNullException">The control ID cannot be null.</exception>
		/// <exception cref="ArgumentException">The control ID is required.</exception>
		public DatePickerAnimation(string controlId) {
			if(controlId == null) throw new ArgumentNullException("controlId");
			if(controlId.Length == 0) throw new ArgumentException("Value is reqired.", "controlId");

			standardAnimation = DatePickerStandardAnimation.Show;
			this.controlId = controlId;
		}


		#endregion


		#region Properties

		/// <summary>
		/// Gets the the standard animation to use, if applicable.
		/// </summary>
		public DatePickerStandardAnimation? StandardAnimation {
			get { return controlId == null ? standardAnimation : (DatePickerStandardAnimation?)null; }
		}

		/// <summary>
		/// Gets the ID of a server effect definition to use, if applicable.
		/// </summary>
		public string ControlId {
			get { return controlId; }
		}

		#endregion


		#region Methods: Object management

		/// <summary>
		/// Determines whether or not the specified object is equal to the current <see cref="DatePickerAnimation"/> value.
		/// </summary>
		/// <param name="obj">The <see cref="Object"/> to compare.</param>
		/// <returns>Whether or not the provided object is equal.</returns>
		public override bool Equals(object obj) {
			if(obj is DatePickerAnimation) return this == (DatePickerAnimation)obj;
			return false;
		}

		/// <summary>
		/// Determines whether or not the specified <see cref="DatePickerAnimation"/> is equal to the current <see cref="DatePickerAnimation"/> value.
		/// </summary>
		/// <param name="other">The <see cref="DatePickerAnimation"/> to compare.</param>
		/// <returns>Whether or not the provided <see cref="DatePickerAnimation"/> value is equal.</returns>
		public bool Equals(DatePickerAnimation other) {
			return this == other;
		}

		/// <summary>
		/// Serves as a hash function for <see cref="DatePickerAnimation"/>.
		/// </summary>
		/// <returns>The hash value associated with the contained data.</returns>
		public override int GetHashCode() {
			//TODO: Have TheMuuj check it.
			return controlId == null ? standardAnimation.GetHashCode() : controlId.GetHashCode();
		}

		/// <summary>
		/// Returns a <see cref="String"/> that represents the current <see cref="DatePickerAnimation"/> value.
		/// </summary>
		/// <returns>The string representation.</returns>
		public override string ToString() {
			return controlId ?? standardAnimation.ToString();
		}

		/// <summary>
		/// Returns a literal JavaScript value used to represent the server value on the client.
		/// </summary>
		/// <returns>The client script value.</returns>
		public string ToClientSource() {
			if(controlId == null) return standardAnimation.ToClientSource();
			return ScriptBuilder.NullLiteral;
		}

		#endregion


		#region Operators

		/// <summary>
		/// Compares the equality of two <see cref="DatePickerAnimation"/> values.
		/// </summary>
		/// <param name="value0">The first value.</param>
		/// <param name="value1">The second value.</param>
		/// <returns>Whether or not the two values are equal.</returns>
		public static bool operator ==(DatePickerAnimation value0, DatePickerAnimation value1) {
			return value0.standardAnimation == value1.standardAnimation && value0.controlId == value1.controlId;
		}

		/// <summary>
		/// Compares the inequality of two <see cref="DatePickerAnimation"/> values.
		/// </summary>
		/// <param name="value0">The first value.</param>
		/// <param name="value1">The second value.</param>
		/// <returns>Whether or not the two values are distinct.</returns>
		public static bool operator !=(DatePickerAnimation value0, DatePickerAnimation value1) {
			return value0.standardAnimation != value1.standardAnimation || value0.controlId != value1.controlId;
		}

		#endregion


	}

}